/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package bakenote.core;

import org.apache.pivot.collections.ArrayList;
import org.apache.pivot.collections.List;

/**
 * @author lello
 */
public class Formula {

    private String name;
    private double percent = 1.0d;
    private double amount = 1000.0d;
    private String units = "g";
    private List<Ingredient> ingredients = new ArrayList<Ingredient>();

    public boolean AUTOPERCENT = true;
    public boolean HAS_PERCENT;
    public boolean HAS_WEIGHTS;

    /**
     * Copy constructor
     */
    public Formula(Formula f) {
        this.name = f.getName();
        this.amount = f.getAmount();
        this.percent = f.getPercent();
        // we must clear the list or we add ingredients to some previously generated list.
        //System.out.println("formula ing length "+this.ingredients.getLength());
        for (Ingredient ing : f.getIngredients()) {
            // copy contructor of Ingredient
            this.ingredients.add(new Ingredient(ing));
        }

        //installListener();
    }


    public Formula(String fname, List<Ingredient> in) {
        this.name = fname;
        for (int i = 0; i < in.getLength(); i++) {
            ingredients.add(in.get(i));
        }
        //installListener();
        setAmount();
        scale(amount);

        if (AUTOPERCENT) SetPercent();
    }

    public Formula(List<Ingredient> in) {
        for (int i = 0; i < in.getLength(); i++) {
            ingredients.add(in.get(i));
        }
        //installListener();
        setAmount();
        scale(amount);

        if (AUTOPERCENT) SetPercent();
    }

    public Formula(String[] s, Amount[] p) {
        if (s.length != p.length) {
            //System.out.println("Error");
            return;
        }
        for (int i = 0; i < p.length; i++) {
            //System.out.print(p[i]);
            //System.out.println("   "+s[i]);
        }
        for (int i = 0; i < p.length; i++) {
            ingredients.add(new Ingredient(s[i], p[i]));
        }
        //installListener();
        setAmount();
        scale(amount);
        if (AUTOPERCENT) SetPercent();
    }

    public Formula() {
        // just allocate a new empty formula do nothing
        //installListener();
    }

    /**
     * private void installListener() {
     * <p/>
     * ingredients.getListListeners().add(new ListListener.Adapter() {
     *
     * @Override public void itemUpdated(List list, int i, Object o) {
     * //To change body of implemented methods use File | Settings | File Templates.
     * Ingredient previousIngredient = (Ingredient) o;
     * if (previousIngredient.getAmount().isMeasurable()) {
     * for (Ingredient ing : ingredients) {
     * if (ing.getAmount().isMeasurable()) {
     * double newAmount = (ing.getExactPercent() / previousIngredient.getExactPercent()) * previousIngredient.getAmount().getDouble();
     * ing.setAmount(newAmount);
     * }
     * }
     * }
     * // update the total amount of the formula
     * setAmount();
     * }
     * <p/>
     * });
     * }  *
     */

    public String getName() {
        return name;
    }

    public void setName(String s) {
        name = s;
    }

    public void setAmount(double a) {
        amount = a;
        scale();
    }

    public double getAmount() {
        double fa = 0.0d;
        for (Ingredient in : ingredients) {
            fa += in.getMeasurableAmount();
        }
        return fa;
    }

    public String getUnits() {
        return units;
    }

    public void setUnits(String units) {
        this.units = units;
    }

    public void addIngredient(Ingredient ing) {
        ingredients.add(ing);
    }

    public List<Ingredient> getIngredients() {
        return ingredients;
    }

    public void setIngredients(List<Ingredient> inglist) {
        ingredients = inglist;
    }

    public Ingredient getIngredient(int i) {
        return ingredients.get(i);
    }

    public Ingredient getIngredient(String s) {
        int index = 0;
        for (int i = 0; i < ingredients.getLength(); i++) {
            if (ingredients.get(i).getName().equals(s)) {
                index = i;
                break;
            }
        }
        return ingredients.get(index);
    }

    public void setIngredient(Ingredient ing, int i) {
        ingredients.get(i).setIngredient(ing);
    }

    public void removeIngredient(int i) {
        ingredients.remove(i, 1);
    }

    private void scale(double w) {
        double xt = xtot(); // total percentage
        double wf = 100.0d * w / xt;
        double wp;
        for (Ingredient in : ingredients) {
            if (in.getAmount().isMeasurable()) {
                wp = (in.getPercent() / 100.0d) * wf;
                //in.setAmount(Amount.valueOf(wp)); // after scaling the weights of the ingredients is available in W
                in.setAmount(wp); // after scaling the weights of the ingredients is available in W
            }
        }
    }

    public void scale() {
        //System.out.println("scaling default amount "+amount);
        double xt = xtot(); // total percentage
        double wf = amount / xt;
        double wp;
        for (Ingredient in : ingredients) {
            if (in.getAmount().isMeasurable()) {
                wp = (in.getPercent()) * wf;
                in.setAmount(wp); // after scaling the weights of the ingredients is available in W
            }
        }
    }

    // This function automagically finds the baker's percent
    private void SetPercent() {

        double xf = 0.0d;
        // If no ingredient has been set as reference that we use an automatic procedure.
        AUTOPERCENT = true;
        for (Ingredient in : ingredients) {
            if (in.isReference()) {
                AUTOPERCENT = false;
                xf += in.getMeasurableAmount();
            }
        }

        if (AUTOPERCENT) {
            // double xf = 0.0d;
            // Chech for flour as reference ingredient
            for (Ingredient in : ingredients) {
                String s = in.getName().toLowerCase();
                if (s.contains("flour") || s.contains("farin")) {
                    in.setReference(true);
                    xf += in.getMeasurableAmount();
                    //System.out.println("XF "+xf);
                }
            }
            // if no flour or eggs are found set the reference ingredient to the one with the
            // largest quantity.
            if (xf == 0.0d) {
                Ingredient xing = ingredients.get(0);
                for (Ingredient in : ingredients) {
                    if (xing.getAmount().isMeasurable() && in.getAmount().isMeasurable()) {
                        if (xing.getAmount().getDouble() < in.getAmount().getDouble()) {
                            xing = in;
                        }
                    }
                }
                xf = xing.getAmount().getDouble();
            }
        }

        // Compute percent
        for (Ingredient in : ingredients) {
            if (in.getAmount().isMeasurable()) {
                double f = in.getAmount().getDouble();
                in.setPercent(f / xf);
                in.setExactPercent(f / xf);
            }
        }
    }

    public void BakersPercent() {
        SetPercent();
    }

    public void setPercent(double f) {
        percent = f;
    }

    public double getPercent() {
        return percent;
    }

    double xtot() {
        double s = 0.0d;
        for (Ingredient in : ingredients)
            s = s + in.getPercent();
        return s;
    }

    //private void setAmount() {
    public void setAmount() {
        //System.out.println("updating amount...");
        double s = 0.0d;
        for (Ingredient in : ingredients)
            s = s + in.getMeasurableAmount();
        amount = s;
    }

    public int length() {
        return ingredients.getLength();
    }

    public boolean contains(String s) {
        // not yet implemented
        if (name.toLowerCase().contains(s.toLowerCase())) {
            return true;
        }
        boolean good = false;
        for (Ingredient ing : ingredients) {
            if (ing.contains(s)) {
                good = true;
                break;
            }
        }
        return good;
    }

}